package com.ie.cloud.payment.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.icbc.api.response.BillLoadResponseV1;
import com.icbc.api.response.BillSingleModifyResponseV1;
import com.icbc.api.response.BillSingleQueryResponseV1;
import com.ie.cloud.payment.cache.RedisUtil;
import com.ie.cloud.payment.constants.BizStatus;
import com.ie.cloud.payment.constants.CS;
import com.ie.cloud.payment.dto.GeneralOrderDto;
import com.ie.cloud.payment.dto.MerchantOrderRecordAdd;
import com.ie.cloud.payment.entity.MchApp;
import com.ie.cloud.payment.entity.MerchantOrderRecord;
import com.ie.cloud.payment.entity.PayOrder;
import com.ie.cloud.payment.exception.BizException;
import com.ie.cloud.payment.mapper.MchAppMapper;
import com.ie.cloud.payment.mapper.MerchantOrderRecordMapper;
import com.ie.cloud.payment.mapper.PayOrderMapper;
import com.ie.cloud.payment.request.MyBillLoadRequestV1;
import com.ie.cloud.payment.request.MyBillSingleModifyRequestV1;
import com.ie.cloud.payment.request.MyBillSingleQueryRequestV1;
import com.ie.cloud.payment.request.MyEPaymentBillRequestV1;
import com.ie.cloud.payment.utils.IdUtils;
import com.ie.cloud.payment.vo.ActivatePaymentResponseVo;
import com.ie.cloud.payment.vo.MyBillSingleQueryResponseVo;
import com.ie.cloud.payment.vo.base.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.ie.cloud.payment.constants.BizStatus.PAY_SUCCESS_NOT_MODIFY_AMOUNT;

/**
 * Created with FR
 *
 * @Author: DQ
 * @Date: 2025/07/16/20:23
 * @Description: 支付订单表 服务实现类
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class PayOrderService extends ServiceImpl<PayOrderMapper, PayOrder> {


    public static final int ORDER_EXPIRED_TIME_OF_SECOND = 30 * 60;

    @Resource
    private PayOrderMapper payOrderMapper;
    @Resource
    private MerchantOrderRecordMapper merchantOrderRecordMapper;
    @Resource
    private MchAppMapper mchAppMapper;
    @Resource
    private ICBCServiceImpl icbcService;


    /**
     * 更新订单为 超时状态
     **/
    public Integer updateOrderExpired() {

        PayOrder payOrder = new PayOrder();
        payOrder.setState(PayOrder.STATE_CLOSED);

        return baseMapper.update(payOrder,
                PayOrder.gw()
                        .in(PayOrder::getState, Arrays.asList(PayOrder.STATE_INIT, PayOrder.STATE_ING))
                        .le(PayOrder::getExpiredTime, new Date())
        );
    }

    /**
     * 订单生成
     **/
    public Result<JSONObject> generateAnOrder(MerchantOrderRecordAdd add) {
        //订单有效期
        LocalDateTime expiredTimeOfOrder = LocalDateTime.now().plusSeconds(ORDER_EXPIRED_TIME_OF_SECOND);


        long currentTimeMillis = System.currentTimeMillis();//当前线程时间戳

        MchApp mchApp = mchAppMapper.selectOne(new LambdaQueryWrapper<MchApp>().eq(MchApp::getAppId, add.getAppId()));


        if (mchApp == null) {
            throw new BizException(BizStatus.MERCHANT_DOES_NOT_EXIST);
        }

        //判断业务类型是否正确
        MerchantOrderRecord record = new MerchantOrderRecord();
        if (!add.getBizType().equals(MerchantOrderRecord.BIZ_TYPE.ElectricityBill)) {
            throw new BizException(BizStatus.BIZ_TYPE_ERROR);
        }
        BeanUtil.copyProperties(add, record);


        //业务类型(租户计费)+业务编号(账单号)+创建时间戳  ===> 商户订单号
        StringBuilder bizBill = new StringBuilder()
                .append(CS.PREFIX_CODE.ORDER_PREFIX)
                .append(record.getBizType())
                .append(record.getBizCode());


        //服务商号
        JSONObject jsonObject = new JSONObject();
        try {


            String payOrderId = IdUtils.getId(18);//支付订单号


            //只会有一个订单号绑定账单号
            boolean nx = RedisUtil.setNx(CS.getCacheKeyOrderId(bizBill.toString()),
                    payOrderId, -1);//30min 有效


            if (nx) {
                record.setExpiredTime(expiredTimeOfOrder);//设置订单有效期
                merchantOrderRecordMapper.insert(record);

                //不存在
                PayOrder payOrder = new PayOrder();
                payOrder.setPayOrderId(payOrderId);
                BeanUtil.copyProperties(add, payOrder);
                payOrder.setMchOrderNo(bizBill.toString());
                payOrder.setMchNo(mchApp.getMchNo());
                payOrder.setExpiredTime(expiredTimeOfOrder);//设置订单有效期
                payOrderMapper.insert(payOrder);

            }
            String orderId = RedisUtil.getString(CS.getCacheKeyOrderId(bizBill.toString()));
            jsonObject.put(CS.ORDER_CACHE.ORDER_ID, orderId);
            jsonObject.put(CS.ORDER_CACHE.MCH_ORDER_NO, bizBill.toString());
            jsonObject.put(CS.ORDER_CACHE.EXL_DATA, orderId);
            log.info("订单号生成成功");

            return Result.success(jsonObject);
        } catch (Exception e) {
            RedisUtil.del(CS.getCacheKeyOrderId(bizBill.toString()));
            log.error("订单生成错误 {}", e.getMessage());
            throw new BizException(BizStatus.ORDER_GENERATION_FAILED);
        }


    }


    /**
     * 订单导入
     *
     * @param payOrderId 订单号
     * @param add        订单信息
     */
    public Result<Integer> billLoadRequest(String payOrderId, MerchantOrderRecordAdd add) {
        MchApp mchApp = mchAppMapper.selectOne(new LambdaQueryWrapper<MchApp>().eq(MchApp::getAppId, add.getAppId()));


        if (mchApp == null) {
            throw new BizException(BizStatus.MERCHANT_DOES_NOT_EXIST);
        }
        MyBillLoadRequestV1 billLoadRequestV1 = getMyBillLoadRequestV1(add, payOrderId, mchApp);
        GeneralOrderDto<MyBillLoadRequestV1> orderDto = new GeneralOrderDto<>();
        orderDto.setAppId(mchApp.getAppId());
        orderDto.setSignSecret(mchApp.getAppSecret());
        orderDto.setApiGwPublicKey(mchApp.getAppPublicKey());
        orderDto.setAesKey(mchApp.getAppAesKey());
        orderDto.setExaData(billLoadRequestV1);
        orderDto.setIfCode("icbcpay");
        // 调用缴费账单导入
        BillLoadResponseV1 billLoadResponseV1 = icbcService.billLoadRequestV1(orderDto, payOrderId);

        if (billLoadResponseV1.isSuccess()) {
            return Result.success(BizStatus.ORDER_IMPORT_SUCCESS.getCode(), billLoadResponseV1.getReturnMsg());
        } else {
            return Result.error(billLoadResponseV1.getReturnCode(), billLoadResponseV1.getReturnMsg());
        }

    }


    /**
     * 缴费大厅账单(RSA2方式)
     *
     * @param payOrderId 订单号
     * @param appId      应用id
     * @return 返回的html 超文本信息
     */
    public String billRequestV1Function(String payOrderId, String appId, String userId) {
        MchApp mchApp = mchAppMapper.selectOne(new LambdaQueryWrapper<MchApp>().eq(MchApp::getAppId, appId));

        if (mchApp == null) {
            throw new BizException(BizStatus.MERCHANT_DOES_NOT_EXIST);
        }
        GeneralOrderDto<MyEPaymentBillRequestV1> orderDto = new GeneralOrderDto<>();
        MyEPaymentBillRequestV1 myEPaymentBillRequestV1 = new MyEPaymentBillRequestV1();


        // 请求参数 设置
        myEPaymentBillRequestV1.setProjectId(mchApp.getProjectId());
        myEPaymentBillRequestV1.setUserId(userId);

        //通用请求参数 设置
        orderDto.setAppId(mchApp.getAppId());
        orderDto.setSignSecret(mchApp.getAppSecret());
        orderDto.setAesKey(mchApp.getAppAesKey());
        orderDto.setIfCode("icbcpay");

        orderDto.setExaData(myEPaymentBillRequestV1);

        return icbcService.EPaymentBillRequestV1Function(orderDto, payOrderId);

    }

    /**
     * 缴费平台单笔账单查询
     *
     * @param appId   应用id
     * @param orderId 订单号
     */
    public Result<MyBillSingleQueryResponseVo> billSingleQuery(String appId, String orderId) {
        MchApp mchApp = mchAppMapper.selectOne(new LambdaQueryWrapper<MchApp>().eq(MchApp::getAppId, appId));

        if (mchApp == null) {
            throw new BizException(BizStatus.MERCHANT_DOES_NOT_EXIST);
        }

        MyBillSingleQueryRequestV1 request = new MyBillSingleQueryRequestV1();
        GeneralOrderDto<MyBillSingleQueryRequestV1> dto = new GeneralOrderDto<>();
        dto.setExaData(request);


        // 设置通用参数
        dto.setAppId(mchApp.getAppId());
        dto.setSignSecret(mchApp.getAppSecret());
        dto.setApiGwPublicKey(mchApp.getAppPublicKey());
        dto.setAesKey(mchApp.getAppAesKey());
        dto.setIfCode("icbcpay");

        //设置 请求参数
        request.setCorpCis(mchApp.getMchNo());
        request.setProjectId(mchApp.getProjectId());
        request.setBatchNo(orderId);
        request.setBillNo("1");

        BillSingleQueryResponseV1 queryResponseV1 = icbcService.EPayBillSingleQuery(dto);

        MyBillSingleQueryResponseVo queryResponse = new MyBillSingleQueryResponseVo();

        BeanUtil.copyProperties(queryResponseV1, queryResponse, true);
        queryResponse.setPayOrderId(orderId);
        if (queryResponseV1.isSuccess()) {

            return Result.success(queryResponse, BizStatus.ORDER_QUERY_SUCCESSFUL.getMsg());
        } else {
            return Result.error(BizStatus.ORDER_QUERY_FAILED.getCode(), queryResponse, BizStatus.ORDER_QUERY_FAILED.getMsg());
        }

    }


    /**
     * 单笔修改
     *
     * @param appId      应用id
     * @param payOrderId 订单号
     * @param billAmount 金额
     * @param billCaeseDate     修改时间
     */
    public Result<BillSingleModifyResponseV1> billSingleModify(String appId, String payOrderId, Long billAmount, String billCaeseDate) {
        MchApp mchApp = mchAppMapper.selectOne(new LambdaQueryWrapper<MchApp>().eq(MchApp::getAppId, appId));
        BillSingleModifyResponseV1 billSingleModifyResponseV1 = new BillSingleModifyResponseV1();
        if (mchApp == null) {
            throw new BizException(BizStatus.MERCHANT_DOES_NOT_EXIST);
        }

        PayOrder payOrder = payOrderMapper.selectOne(PayOrder.gw().eq(PayOrder::getPayOrderId, payOrderId));
        if (payOrder == null) {
            throw new BizException(BizStatus.PAY_ORDER_NOT_EXIST);
        }
        if (payOrder.getState().equals(PayOrder.STATE_SUCCESS)) {
            //支付成功，金额不能修改
            throw new BizException(PAY_SUCCESS_NOT_MODIFY_AMOUNT);
        }
        if (payOrder.getState().equals(PayOrder.STATE_REFUND)) {
            throw new BizException("订单已退费,无法更改金额");
        }
        if (payOrder.getAmount().equals(billAmount)){
            return Result.success(billSingleModifyResponseV1);
        }

        //情况1,订单10元,未缴纳,更改订单15元
        //情况2,订单10元,缴纳5元,更改订单15元
        //情况3,订单10元,未缴纳,更改订单5元
        //情况4,订单10元,缴纳5元,更改订单5元
        //以上两种情况都可以修改金额

        try {
            //更新订单表
            PayOrder updatePayOrder = new PayOrder();
            updatePayOrder.setAmount(billAmount);
            payOrderMapper.update(updatePayOrder, PayOrder.gw().eq(PayOrder::getPayOrderId, payOrderId));

            MyBillSingleModifyRequestV1 request = new MyBillSingleModifyRequestV1();

            GeneralOrderDto<MyBillSingleModifyRequestV1> dto = new GeneralOrderDto<>();

            //通用参数设置
            dto.setAppId(mchApp.getAppId());
            dto.setSignSecret(mchApp.getAppSecret());
            dto.setApiGwPublicKey(mchApp.getAppPublicKey());
            dto.setAesKey(mchApp.getAppAesKey());
            dto.setIfCode("icbcpay");


            //修改参数设置
            request.setCorpCis(mchApp.getMchNo());
            request.setProjectId(mchApp.getProjectId());
            request.setBillAmount(billAmount);
            request.setBillCaeseDate(billCaeseDate);
            request.setBusiCode(payOrderId);

            dto.setExaData(request);

            billSingleModifyResponseV1 = icbcService.EPayBillSingleModify(dto, payOrderId);

            if (billSingleModifyResponseV1.isSuccess()) {
                return Result.success(billSingleModifyResponseV1);
            }else {
                return Result.error(billSingleModifyResponseV1.getReturnCode(), billSingleModifyResponseV1.getReturnMsg());
            }
        }catch (Exception e) {
            log.error("修改订单错误 {}",e.getMessage());
            throw new BizException(e.getMessage());
        }
    }


    /**
     * 查询商户订单
     **/
    public PayOrder queryMchOrder(String payOrderId, String mchOrderNo) {

        if (StringUtils.isNotEmpty(payOrderId)) {
            return getOne(PayOrder.gw().eq(PayOrder::getPayOrderId, payOrderId).eq(PayOrder::getMchOrderNo, mchOrderNo));
        } else {
            return null;
        }
    }


    /**
     * 更新订单状态(兜底)
     */
    public void updateToSuccessOrder(String trxDate) {
        payOrderMapper.updatePayOrderState(trxDate);
    }


    /**
     * 唤起支付
     *
     * @param add 订单信息
     */
    public Result<ActivatePaymentResponseVo<MerchantOrderRecordAdd>> activatePayment(MerchantOrderRecordAdd add) {
        log.info("唤起支付开始");


        Result<ActivatePaymentResponseVo<MerchantOrderRecordAdd>> responseVoResult =
                new Result<>();

        ActivatePaymentResponseVo<MerchantOrderRecordAdd> activatePaymentResponseVo = new ActivatePaymentResponseVo<>();
        responseVoResult.setData(activatePaymentResponseVo);
        activatePaymentResponseVo.setExaData(add);


        try {
            Result<JSONObject> order = generateAnOrder(add);
            if (order.getCode() == HttpStatus.HTTP_OK) {
                log.info("生成的订单信息============> {}", order.getData());

                if (order.getData() == null) {
                    throw new BizException(BizStatus.ORDER_GENERATION_FAILED);
                }

                String orderId = order.getData().get(CS.ORDER_CACHE.ORDER_ID).toString();
                activatePaymentResponseVo.setPayOrderId(orderId);


                Result<Integer> billLoadRequest = billLoadRequest(orderId, add);
                log.info("账单导入信息============> {}", billLoadRequest);
                if (billLoadRequest.getCode() == HttpStatus.HTTP_OK ||
                        billLoadRequest.getCode() == BizStatus.THE_CORRESPONDING_BILLING_BATCH_RECORD_ALREADY_EXISTS.getCode()) {
                    log.info("账单导入信息返回信息============> {}", billLoadRequest.getData());


                    Result<BillSingleModifyResponseV1> singleModify = billSingleModify(add.getAppId(), orderId, add.getAmount(), LocalDate.now().toString());
                    if (singleModify.getCode() == HttpStatus.HTTP_OK) {
                        String htmlContent = billRequestV1Function(orderId, add.getAppId(), add.getUserId());

                        log.info("唤起支付结束");
                        activatePaymentResponseVo.setContentHtml(htmlContent);
                    }



                } else {
                    responseVoResult.setMsg(billLoadRequest.getMsg());
                }
                return responseVoResult;
            } else {
                responseVoResult.setMsg(order.getMsg());
                return responseVoResult;
            }
        } catch (BizException e) {
            log.error("唤起支付失败 {}", e.getMessage());
            throw new BizException(e.getCode(), e.getMessage());
        }
    }



    /**
     * 获取所有订单id和商户订单号
     */
    public Map<String, Object> GetPayOrderId() {

        List<PayOrder> payOrders = payOrderMapper.selectInfoList();

        Map<String, Object> map = new HashMap<>(payOrders.size());
        for (PayOrder payOrder : payOrders) {
            map.put(CS.getCacheKeyOrderId(payOrder.getMchOrderNo()), payOrder.getPayOrderId());
        }
        return map;
    }


    private static MyBillLoadRequestV1 getMyBillLoadRequestV1(MerchantOrderRecordAdd add, String payOrderId, MchApp mchApp) {
        MyBillLoadRequestV1 billLoadRequestV1 = new MyBillLoadRequestV1();
        billLoadRequestV1.setBatchNo(payOrderId);
        billLoadRequestV1.setCorpCis(mchApp.getMchNo());
        billLoadRequestV1.setProjectId(mchApp.getProjectId());
        billLoadRequestV1.setEbppFlag("1");
        billLoadRequestV1.setBillName(add.getSubject());
        billLoadRequestV1.setTotalAmt(new BigDecimal(add.getAmount()));
        billLoadRequestV1.setTotalNum("1");
        billLoadRequestV1.setFetchNum("1");
        billLoadRequestV1.setStartNum("1");
        billLoadRequestV1.setBillDate(add.getCreatedAt().toLocalDate().toString());
        billLoadRequestV1.setBillAmount(new BigDecimal(add.getAmount()));
        billLoadRequestV1.setBillList(new ArrayList<>());
        return billLoadRequestV1;
    }


}
